/* -----------------------------------------------------------------------
 *   Copyright (C) 2008 by Denjs
 *   dplsoft@pisem.net
 *   http://qdroid.berlios.de
 * -----------------------------------------------------------------------
 *   This program is free software licensed under GNU GPL License v.2 ; see main.cpp fo details
 *   Эта программа является свободным программным обеспечением; распространяемым под
 *   лицензией GNU General Public License v.2 (УНИВЕРСАЛЬНАЯ ОБЩЕСТВЕННАЯ ЛИЦЕНЗИЯ GNU версия 2.0)
 * ----------------------------------------------------------------------- */
/*
 * t_QDLibManager.cpp
 *
 *  Created on: 2009.04.28
 *      Author: Denjs
 *
 *  Класс инкапсулирующий функции управления
 *  библиотеками содержащими расширения среды qDOID
 *   - "боты" и функции
 *   
 *
 * ver 209.07.29 добавлены уровни отладки   
 */

#include "t_QDLibManager.h"

//============================================================
t_QDLibManager::t_QDLibManager(QScriptEngine *_QSEngine, QObject *_Parent)
		: QObject(_Parent)
{
	  DebugLevel=1;
		QSEngine=_QSEngine; // менеджер расширений "не мыслим" без скриптового движка с которым он работает...
      	libdirname="."; // не нужны нам пока подкаталоги

		// Linux:
		#if defined (Q_WS_X11)
			libfilenamePrefix="";//LINUX::только имя - без префикса (lib~) и расширения или суффикса "~.so", "~.dll"

		// Win:
		#elif defined (Q_WS_WIN)
			libfilenamePrefix="";//WIN:: имя - c префиксом (lib~) но без расширения или суффикса "~.so", "~.dll"

		// Mac:
		#elif defined (Q_WS_MAC)
				// NOT SUPPORTED THIS VERSION
		#else
				// NOT SUPPORTED THIS VERSION
		#endif

}

//============================================================
//загрузить библиотеку с именем LibName
/* типичная QDR-идеология кодов ошибок:
   0=ok
   -1=error
   +1=warning
*/
/*

*/
int t_QDLibManager::load_lib(QString LibName)
{
        //QLibrary  lib; // Боюсь что это должна быть глобальная переменная или массив... как бы библиотека не выгрузилась при уничтожении данной переменной после выхода из функции.
        QString tmpstr;

        LastErrCode=0; //++2011.03.11
        LastErrMessage=QString().append("no errors <LoadQDroidLibrary::00064: reseted error code due starting toloading lib %1>").arg(LibName);

        LibDefItem LibToLoad;
        LibToLoad.lib = new QLibrary();//TODO возможно сюда передать родителя что бы "уничтожить" объект когда надо?
        //========================================================================
        //  часть 1 - загрузка библиотеки и проверка нужных функций
        //========================================================================
      // 1 - только ошибки
      // 2 - лог работы
      // 3 - подробный лог
      // 4 с дампом ключевых данных
			if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0042: [1] Looking for dirs.";

				// не очень хороший шаг - в виндоус работатеь так не будет, но пока переделывать нет времени и желания... ::
				//"поднамилежащие" системы в suse отдают почему-то русское сообщение и присем в UTF...
                                // (потому что консоль в UTF8???)
				// приходится декодировать обратно то что рассматривается как latin1 хотя на самом деле utf8
				QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

                                QTextCodec *localeCodec = QTextCodec::codecForName("UTF-8");//ISO 8859-1");
                                #if defined (Q_OS_WIN32)    // для виндовой "консоли-локали" всегда так
                                    localeCodec = QTextCodec::codecForName("IBM 866");//это ля консоли
                                #endif

				LibToLoad.name = LibName;
				LibToLoad.fname = QString(""+QApplication::applicationDirPath()+"/"+libdirname+"/"+libfilenamePrefix+LibName);
                                LibToLoad.lib->setFileName(LibToLoad.fname);
                                LibToLoad.lib->setLoadHints(QLibrary::ExportExternalSymbolsHint|QLibrary::ResolveAllSymbolsHint);

				//lbl.append(QString("application dir: ["+QApplication::applicationDirPath()+"] \n"));
				if (DebugLevel>=3) qDebug() << QString("LoadQDroidLibrary::0073: application dir: ["+QApplication::applicationDirPath()+"] \n");

			if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0075: [2] Initializing libraries-subsystem...";

				// тут скорее всего выдадим отрицательный результат...
				if (! LibToLoad.lib->isLibrary(LibToLoad.lib->fileName()))
					{ //ERROR!
					 //lbl.append(QString("<<lib ["+LibToLoad.lib->fileName()+"] NOT a library::"+QString(codec->fromUnicode(LibToLoad.lib->errorString()))+">> \n"));
                                         if (DebugLevel>=3) qDebug()<< QString("LoadQDroidLibrary::0081: <<lib ["+LibToLoad.lib->fileName()+"] NOT a library::"+LibToLoad.lib->errorString()+">> \n");//QString(codec->fromUnicode(LibToLoad.lib->errorString()))
					}
				   else
					{
					 //lbl.append(QString("<<lib "+LibToLoad.lib->fileName()+" FOUND as a library::"+QString(codec->fromUnicode(LibToLoad.lib->errorString()))+">> \n"));
                                         if (DebugLevel>=3) qDebug()<< QString("LoadQDroidLibrary::0086: <<lib "+LibToLoad.lib->fileName()+" FOUND as a library::"+LibToLoad.lib->errorString()+ ">> \n");//QString(codec->fromUnicode(LibToLoad.lib->errorString()))
					};

			if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0089: [3] finding and loading library ...";

				// а тут уже будет подобрано реaльно существующее имя - и значение LibToLoad.lib->fileName() изменится.
				if (! LibToLoad.lib->load())
					{
					 //lbl.append("<<lib "+LibToLoad.lib->fileName()+" NOT loaded:: "+QString(codec->fromUnicode(LibToLoad.lib->errorString()))+">> \n");
                                         if (DebugLevel>=1) qDebug() << "LoadQDroidLibrary::0095: <<lib " << LibToLoad.lib->fileName() << " NOT loaded:: " << LibToLoad.lib->errorString() << ">> \n"; //QString(codec->fromUnicode(LibToLoad.lib->fileName()))
                                         return -1; //2011.05.15 added  (при отсутствии файла как данность надо срау вываливаться)
					}
				   else
					{
					 //lbl.append("<<lib "+LibToLoad.lib->fileName()+" Loaded:: "+QString(codec->fromUnicode(LibToLoad.lib->errorString()))+">>  \n");
                                         if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0100: <<lib "  << LibToLoad.lib->fileName()  << " Loaded:: "  <<LibToLoad.lib->errorString() << ">>  \n"; //QString(codec->fromUnicode(LibToLoad.lib->errorString()))
					};

			// такое расширение уже загружено. Ничего больше делать не будем. Не стоит по 2 раза регистрировать одни и те-же расширения в движке.
			if (LoadedLibMap.contains(LibToLoad.fname))
					{
                                          LastErrCode=10;//не все так плохо как могло бы быть, но всеже надо сказать)
                                          LastErrMessage=QString().append("WRN::LoadQDroidLibrary::0104: <<lib ").append(LibToLoad.lib->fileName()).append(" Was already loaded and is in use. no registration needs. \n");
						if (DebugLevel>=2) qDebug() << LastErrMessage;//"LoadQDroidLibrary::0104: <<lib "  << LibToLoad.lib->fileName()  << " Was already loaded and is in use. no registration needs. \n";
                                                return 10;
					};

			if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0103: [4] verifing...";

			if (! LibToLoad.lib->isLoaded())
				   {
					  //lbl.append("<<ERROR : lib not loaded:: "+LibToLoad.lib->errorString()+">>  \n");
					  if (DebugLevel>=1) qDebug()  << "LoadQDroidLibrary::0109: <<ERROR : lib not loaded:: "  << LibToLoad.lib->errorString()  << ">>  \n";
                                          return -1; //2011.05.15 added  (при отсутствии файла как данность надо срау вываливаться)
				   }
				  else
				   {
					  //lbl.append("<<OK : lib loaded succesfull:: lib filename ["+LibToLoad.lib->fileName()+"]>>  \n");
					  if (DebugLevel>=3) qDebug()  << "LoadQDroidLibrary::0114: <<OK : lib loaded succesfull:: lib filename ["  << LibToLoad.lib->fileName() << "]>>  \n";
				   };

			if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0117: [5] function solving...";

			// определим ссылки на наши функции

                                typedef int (*T_FLIB_register_class)(QScriptEngine *_QSEngine); //ссылка на функцию регистрации класса
                                //typedef int (*T_FLIB_register_class)(QScriptEngine*,QString); //ссылка на функцию регистрации класса
                                        //ClassName - реально не используется!
                                typedef QObject* (*T_get_object)(ushort*); //получить объект по имени класса

			//	typedef qint32 (*T_send_0)(ushort *_request, ushort * _response_place); //запрос-ответ. За выделение памяти ответственнен вызывающий процесс.
			//	typedef qint32 (*T_get_jobstatus_0)(ushort *_request, ushort * _response_place); //запрос-ответ. За выделение памяти ответственнен вызывающий процесс.
			//	typedef qint32 (*T_get_status_0)(ushort * _response_place); //запрос состояний. За выделение памяти ответственнен вызывающий процесс.
			//	typedef qint32 (*T_get_int_pp_0)();

			if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0129: [6] var initializing...";

                                //QString Response; // эти куски из старого кода работы с библиотеками - а именно передачистрок и получения ответа... здесь не нужно, но пусть пока будет...
                                //ushort * _response_place;
                                //Response.resize(1024);
                                //_response_place=(ushort *)Response.data();
                                ////QString Request="<phtml>HELLO!<br> 1 <br> 2 <br> 3 <br></phtml>";
                                ////QString WaitedJobId="job_1.0";

				//T_init_0	init_0 		= (T_init_0)(LibToLoad.lib->resolve("init_0"));
				// вот они - 2 самых важных функции. Хотя на самом деле критична только вторая.
                                T_get_object 			get_object =0;
                                get_object = (T_get_object)(LibToLoad.lib->resolve("get_object"));

                                T_FLIB_register_class 	FLIB_register_class=0 ;
                                FLIB_register_class = (T_FLIB_register_class)(LibToLoad.lib->resolve("register_class"));

			if (DebugLevel>=3) qDebug() << "LoadQDroidLibrary::0142: [7] calling function...";
			// вызываем функцию из библиотеки


			//	if (DebugLevel>=1) qDebug()<<" ============= get_int_pp_0()="<<get_int_pp_0();
			//	if (init_0)
				if (get_object)
					{
						//lbl.append(" OK::<<functions get_object class was resolved>> ");
						//if (DebugLevel>=3)
						if (DebugLevel>=3) qDebug()<<"LoadQDroidLibrary::0153: OK... function get_object resolved.";
                                                tmpstr=LibToLoad.lib->errorString();
                                                if (DebugLevel>=3) qDebug()<<" ... and errorString()=" << tmpstr;

						////init_0(_response_place);//инициируем систему
						//obj_link=get_object(_response_place);//получаем объект

						//lbl.append("<<object was got through get_object>> ");
						//lbl.append("----------------------------- ");
						//lbl.append(obj_link->objectName());
						//lbl.append("----------------------------- ");
					}
					else
					{ //ERROR!
						//lbl.append("ERROR::<<function get_object not resolved>> \n");
						//if (DebugLevel>=1)
						if (DebugLevel>=1) qDebug()<<"LoadQDroidLibrary::0166: ERROR...function get_object not resolved";
                                                tmpstr=LibToLoad.lib->errorString();
                                                if (DebugLevel>=3) qDebug()<<" ... and errorString()=" << tmpstr;
                                                LibToLoad.lib->unload();// ибо зачем нам библиотека которая не загружена?
						return -2;//QSEngine->undefinedValue();//return -1;
					};

				if (FLIB_register_class)
					{
						//lbl.append("OK::<<functions register_class was resolved>> ");
						//if (DebugLevel>=3)
                                                if (DebugLevel>=3) qDebug()<<"LoadQDroidLibrary::0174: OK... function register_class resolved.";
                                                tmpstr=LibToLoad.lib->errorString();
                                                if (DebugLevel>=3) qDebug()<<" ... and errorString()=" << tmpstr;
                                        }
					else
					{
						//lbl.append("ERROR::<<function register_class not resolved>> \n");
						//if (DebugLevel>=1)
						if (DebugLevel>=1) qDebug()<<"LoadQDroidLibrary::0180: ERROR...function register_class not resolved";
                                                tmpstr=LibToLoad.lib->errorString();
                                                if (DebugLevel>=3) qDebug()<<" ... and errorString()=" << tmpstr;
                                                LibToLoad.lib->unload();// ибо зачем нам библиотека которая не загружена?
						return -2;//QSEngine->undefinedValue();//return -1;
					};

// в новых версиях QDR-компонент этого нет.
//                typedef qint32 (*T_get_int_pp_0)(); //получить объект по имени класса

//                T_get_int_pp_0 FLIB_get_int_pp_0=0;
//                FLIB_get_int_pp_0 = (T_get_int_pp_0)(LibToLoad.lib->resolve("get_int_pp_0"));

//                qDebug() << " LIB :: _get_int_pp_0() = " << FLIB_get_int_pp_0();
//                qDebug() << " LIB :: _get_int_pp_0() = " << FLIB_get_int_pp_0();
//                qDebug() << " LIB :: _get_int_pp_0() = " << FLIB_get_int_pp_0();
//                qDebug() << " LIB :: _get_int_pp_0() = " << FLIB_get_int_pp_0();

			// ===============================================================
			// теперь вроде бы уверены что библиотека загружена и мы можем её использовать...

			//========================================================================
			//  часть 2 - работа со скриптовым движком
			//========================================================================
                                //++QString());//++2010.05.20 bugfixing
                          QString emptyQsrt="";
                          //int rezlb = FLIB_register_class(QSEngine, emptyQsrt);// зарегистрируем классы из библиотеки
                          int rezlb = FLIB_register_class(QSEngine);// зарегистрируем классы из библиотеки
                          //в принципе этого должно быть достаточно

			  LoadedLibMap[LibToLoad.fname]=LibToLoad;
         return 0;


}

//============================================================
//загрузить библиотеку с именем LibName
int t_QDLibManager::unload_lib(QString LibName)
{

    return -1;
}
//============================================================

